﻿using Cms.Core.Application.IService.RoleInfo;
using Cms.Core.Application.Service.RoleInfo.Dto;
using Cms.Core.Data.Model;
using Cms.Core.Data.UnitOfWork;
using Cms.Core.Infrastructure.Common;
using Cms.Core.Infrastructure.Dependency;
using Cms.Core.Infrastructure.Extension;
using Cms.Core.Infrastructure.Helps;
using Cms.Core.Infrastructure.Log;
using Cms.Core.Infrastructure.Runtime.Session;
using Cms.Core.Infrastructure.Ui;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cms.Core.Application.Service.RoleInfo
{
    /// <summary>
    /// 角色接口
    /// </summary>
    public class RoleService : IRoleService
    {
        private readonly IRepository<SysRole> _sysRoleRepository;

        private readonly ILoggerHelper _loggerHelper = null;
        private readonly IRepository<SysUserRoleMap> _sysUserRoleRepositoryMap;
        private readonly IRepository<SysRolePermissionMap> _sysRolePermissionMap;

        private readonly ICmsSession _session = null;
        private readonly Guid? _userId = null;
        private readonly IUnitOfWork _unitOfWork = null;


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sysRoleRepository"></param>
        /// <param name="loggerHelper"></param>
        /// <param name="session"></param>
        /// <param name="sysUserRoleRepositoryMap"></param>
        /// <param name="sysRolePermissionMap"></param>
        public RoleService(IRepository<SysRole> sysRoleRepository, ILoggerHelper loggerHelper, ICmsSession session, IRepository<SysUserRoleMap> sysUserRoleRepositoryMap, IRepository<SysRolePermissionMap> sysRolePermissionMap, IUnitOfWork unitOfWork)
        {
            this._sysRoleRepository = sysRoleRepository;
            this._loggerHelper = loggerHelper;
            this._session = session;
            this._userId = session.UserId;
            this._sysUserRoleRepositoryMap = sysUserRoleRepositoryMap;
            this._sysRolePermissionMap = sysRolePermissionMap;
            this._unitOfWork = unitOfWork;
        }


        /// <summary>
        /// 添加角色
        /// </summary>
        /// <param name="input"></param>
        /// <param name="checkRoleFunc"></param>
        /// <returns></returns>
        public async Task<OperationResult> AddRoleAsync(RoleDto input, Func<string, string, Guid, Task> checkRoleFunc)
        {
            _unitOfWork.BeginTransaction();
             var result= await _sysRoleRepository.InsertAsync(input, async o =>
            {

                await checkRoleFunc.Invoke(o.Name, o.Code, o.Id);

            }, async (dto, r) =>
            {

                r.OrderSort = await MaxOrderSortAsync();
                r.ModifiedUserId = _userId;
                r.CreateUserId = _userId;
                return r;
            },r=> {

                return input;
             });

            if (result.Successed)
            {
                if (input.PermissionIds.Any())
                {
                    result = await this.BatchAddSysRolePermissionMaps(input.PermissionIds,input.Id);
                }
           
            }
            _unitOfWork.Commit();
            return result;

        }

        /// <summary>
        /// 异步更新或者更新角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OperationResult> UpdateOrAddRoleAsync(RoleDto input)
        {
            Func<string, string, Guid, Task> checkRoleFunc = async (name, code, id) =>
              {
                  CheckRoleIsNullOrEmpty(name, code);
                  await CheckRoleIsExistAsync(name, code, id);

              };

            if (input.Id == Guid.Empty)
            {
                return await this.AddRoleAsync(input, checkRoleFunc);
            }
            return await this.UpdateRoleAsync(input, checkRoleFunc);
        }
        /// <summary>
        /// 更新角色异步
        /// </summary>
        /// <param name="input"></param>
        /// <param name="checkRoleFunc"></param>
        /// <returns></returns>
        public async Task<OperationResult> UpdateRoleAsync(RoleDto input, Func<string, string, Guid, Task> checkRoleFunc)
        {
            _unitOfWork.BeginTransaction();

            var result= await _sysRoleRepository.UpdateNotQueryAsync(input, async (dto, role) =>
            {
                await checkRoleFunc.Invoke(dto.Name, dto.Code, dto.Id);
            }, async (dto, r) =>
            {

                r.ModifiedUserId = _userId;
                await Task.CompletedTask;
                return r;
            }, o => o.Name,
              o => o.Code,
              o => o.Description,
              o => o.ModifiedTime,
              o => o.ModifiedUserId,
              o => o.IsEnabled,
              o=>o.IsAdmin);
            if (result.Successed)
            {
                
                if (input.PermissionIds.Any())
                {
                  
     
                    await this._sysRolePermissionMap.SoftDeleteBatchAsync(o =>o.RoleId==input.Id, m => new SysRolePermissionMap()
                    {
                        IsDelete = true
                    });
                    await this.BatchAddSysRolePermissionMaps(input.PermissionIds, input.Id);
                }
               
            }
            _unitOfWork.Commit();
            return result;
        }

        /// <summary>
        /// 得到用户分页信息
        /// </summary>
        /// <param name="pageRequestData">分页请求数据</param>
        /// <returns></returns>

        public async Task<PageResult> GetRolePageDataAsync(PageRequestData pageRequestData)
        {
            pageRequestData.NotNull(nameof(pageRequestData));
            var filter = FilterHelp.ToFilterExpression<SysRole>(pageRequestData.Filters);
            filter.NotNull(nameof(filter));

            var query = await _sysRoleRepository.QueryNotDelete.ToPageAsync(filter, pageRequestData, o => new
            {
                Id = o.Id,
                Name = o.Name,
                Code = o.Code,
                OrderSort = o.OrderSort,
                IsEnabled = o.IsEnabled,
                CreateTime = o.CreateTime,
                ModifiedTime = o.ModifiedTime,
                Description = o.Description,
            });
            return query.ToPageResult();
        }


        /// <summary>
        /// 最大排序号
        /// </summary>
        /// <returns></returns>
        public async Task<int> MaxOrderSortAsync()
        {
            int? maxOrderSort = await _sysRoleRepository.Entities.MaxAsync(o => (int?)o.OrderSort);
            return (maxOrderSort.HasValue ? maxOrderSort.Value + 1 : 0);
        }
        private void CheckRoleIsNullOrEmpty(string roleName, string code)
        {
            if (roleName.IsNullOrWhiteSpace())
            {
                throw new CustomException("角色名不能为空!!");
            }

            if (code.IsNullOrWhiteSpace())
            {
                throw new CustomException("编码不能为空!!");
            }



        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleName"></param>
        /// <param name="code"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        private async Task<bool> CheckRoleIsExistAsync(string roleName, string code, Guid id)
        {
            var isExist = await _sysRoleRepository.Query(role => (role.Name.ToUpper() == roleName.ToUpper() || role.Code.ToUpper() == code.ToUpper()) && (role.Id != (id != Guid.Empty ? id : Guid.Empty))).AnyAsync();

            if (isExist)
            {
                throw new CustomException("该角色已存在！！！");
            }
            return isExist;
        }


        /// <summary>
        /// 异步加载角极
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<OperationResult<RoleDto>> LoadRoleAsync(Guid? id)
        {

            var dto = new RoleDto();
            if (!id.IsEmptyOrNullOrHasValue()) {
                dto = (await _sysRoleRepository.GetDtoAsync<RoleDto>(id.Value));
                dto.PermissionIds = await this._sysRolePermissionMap.QueryNotDelete.Where(o => o.RoleId == id.Value).Select(o => o.PermissionId).ToListAsync();
            }

            //var dto = !id.IsEmptyOrNullOrHasValue() ? (await _sysRoleRepository.GetDtoAsync<RoleDto>(id.Value)) : new RoleDto();
            return new OperationResult<RoleDto>()
            {
                Message = "加载数据成功!!",
                Data = dto,
                Type = OperationResultType.Success,
            };
        }

        /// <summary>
        /// 异步软删除
        /// </summary>
        /// <param name="id">主键ID</param>
        /// <returns></returns>
        public async Task<OperationResult> SoftDeleteRoleAsync(Guid id)
        {

            return await _sysRoleRepository.SoftDeleteAsync(id);
        }

        /// <summary>
        /// 异步得到所有启用的角色数据
        /// </summary>
        /// <returns></returns>
        public async Task<IEnumerable<RoleDto>> GetAllEnableRoleListAsync()
        {
            var roleList = await _sysRoleRepository.QueryToDto<RoleDto>(r => r.IsDelete == false && r.IsEnabled == true).ToListAsync();
            return roleList;
        }


        /// <summary>
        /// 把角色转成选择列表项
        /// </summary>
        /// <returns></returns>
        public async Task<OperationResult<IEnumerable<SelectListItem>>> ToRoleSelectListItem()
        {
            var result = await this.GetAllEnableRoleListAsync();

            IEnumerable<SelectListItem> roleSelectListItem = result.Select(o => new SelectListItem()
            {
                Text = o.Name,
                Value = o.Id.ToString(),

            });
            return new OperationResult<IEnumerable<SelectListItem>>
            {
                Data = roleSelectListItem,
                Message = "查询成功",
                Type = OperationResultType.Success,

            };

        }

        /// <summary>
        /// 异步根据用户得到角色集合
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns></returns>

        public async Task<IEnumerable<SelectListItem>> GetRoleListByUserIdAsync(Guid userId)
        {
            userId.NotEmpty(nameof(userId));

           return (await this.GetUserRolesByUserIdAsync(userId)).Select(o=>new SelectListItem {
                Text=o.Name,
                Value=o.Id.ToString()
            });
        }


        /// <summary>
        /// 异步得到所有用户角色
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<IEnumerable<RoleDto>> GetUserRolesByUserIdAsync(Guid userId)
        {
            userId.NotEmpty(nameof(userId));
            return  await this.GetUserRolesByUserId(userId).ToListAsync();
            //var role = _sysRoleRepository.QueryNotDelete.Where(o => o.IsEnabled == true);
            //var roleList= await _sysUserRoleRepositoryMap.QueryNotDelete.Where(map => map.UserId == userId).Join(role, m => m.RoleId, r => r.Id, (m, r) => r).ToListAsync();
        }



        /// <summary>
        /// 得到所有用户角色(这里应该放在userRole接口下)
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public IQueryable<RoleDto> GetUserRolesByUserId(Guid userId)
        {
            userId.NotEmpty(nameof(userId));
            var role = _sysRoleRepository.QueryNotDelete.Where(o => o.IsEnabled == true);
            return  _sysUserRoleRepositoryMap.QueryNotDelete.Where(map => map.UserId == userId).Join(role, m => m.RoleId, r => r.Id, (m, r) => r).ToDto<SysRole,RoleDto>();
           
        }

        /// <summary>
        /// 得到所角色
        /// </summary>
        /// <returns></returns>
        public IQueryable<SysRole> GetAllRoles()
        {
            return _sysRoleRepository.QueryNotDelete;
        }




        /// <summary>
        /// 异步批量添加
        /// </summary>
        /// <param name="permissionIds"></param>
        /// <param name="roleId"></param>
        /// <returns></returns>

        private async Task<OperationResult> BatchAddSysRolePermissionMaps(IEnumerable<Guid> permissionIds, Guid roleId)
        {
            var sysRolePermissionMaps = permissionIds.Select(o => new SysRolePermissionMap
            {
                PermissionId=o,
                RoleId=roleId,
                CreateUserId = _userId,
                ModifiedUserId = _userId,

            }).ToArray();
            return await _sysRolePermissionMap.InsertAsync(sysRolePermissionMaps);
        }
    }
}
